package pipeline.vertex;

import javax.vecmath.Color3f;
import javax.vecmath.Vector2f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;

import pipeline.Pipeline;
import pipeline.PointLight;
import pipeline.math.Matrix4f;
import pipeline.misc.Vertex;

/**
 * This triangle processor smoothly interpolates the color across the face of
 * the triangle. This is better than flat shading, but still not as nice as
 * fragment (aka phong) shading.
 *
 * @author ags
 */
public class SmoothShadedVP extends ShadedVP
{
        protected Matrix4f m = new Matrix4f();
        protected Matrix4f modelview = new Matrix4f();

        // lighting vectors
        Vector3f E = new Vector3f(), L = new Vector3f(), N = new Vector3f(), H = new Vector3f(), V = new Vector3f();
       
        // vertex
        Vector4f v2 = new Vector4f(), n2 = new Vector4f();
       
        // Final color
        Color3f c2 = new Color3f();
       
       
        public int nAttr()
        {
                return 3;
        }

        public void updateTransforms(Pipeline pipe)
        {
                modelview.set(pipe.modelviewMatrix);
               
                m.set(pipe.modelviewMatrix);
                m.leftCompose(pipe.projectionMatrix);
                m.leftCompose(pipe.viewportMatrix);
        }

        public void vertex(Vector3f v, Color3f c, Vector3f n, Vector2f not_t, Vertex out)
        {
                //  vertex 
                v2.set(v.x, v.y, v.z, 1);
                modelview.rightMultiply(v2);
                V.set(v2.x, v2.y, v2.z);

                // Normal 
                n2.set(n.x, n.y, n.z, 0);
                modelview.rightMultiply(n2);
               
                E.set(-V.x, -V.y, -V.z);
                E.normalize();
               
                N.set(n2.x, n2.y, n2.z);
                N.normalize();
               
                c2.set(Pipeline.ambientIntensity*c.x, Pipeline.ambientIntensity*c.y, Pipeline.ambientIntensity*c.z);
               
                for(PointLight light : Pipeline.lights) {
                        Color3f lc = light.getIntensity();

                        L.set(light.getPosition());
                        L.sub(V);
                        L.normalize();
                       
                        float dot = L.dot(N);

                        if(dot > 0) {
                                c2.x += c.x*dot*lc.x;
                                c2.y += c.y*dot*lc.y;
                                c2.z += c.z*dot*lc.z;
                        }
                       
                        H.set(L);
                        H.add(E);
                        H.normalize();
                       
                        dot = H.dot(N);
                       
                        if(dot > 0) {
                                dot = (float) Math.pow(dot, Pipeline.specularExponent);
                               
                                c2.x += dot*Pipeline.specularColor.x;
                                c2.y += dot*Pipeline.specularColor.y;
                                c2.z += dot*Pipeline.specularColor.z;
                        }
                }
               
                // Clamp
                if(c2.x > 1) {
                        c2.x = 1;
                }
                if(c2.y > 1) {
                        c2.y = 1;
                }
                if(c2.z > 1) {
                        c2.z = 1;
                }
               
                out.v.set(v.x, v.y, v.z, 1);
                m.rightMultiply(out.v);
               
                out.setAttrs(nAttr());
                out.attrs[0] = c2.x;
                out.attrs[1] = c2.y;
                out.attrs[2] = c2.z;
        }
       
        public void triangle(Vector3f[] v, Color3f[] c, Vector3f[] n, Vector2f[] t, Vertex[] out)
        {
                for (int k = 0; k < 3; k++) {
                        vertex(v[k], c[k], n[k], t[k], out[k]);
                }
        }
}

